import * as THREE from 'three'
import { gsap } from 'gsap'
import * as dat from 'dat.gui'
import { Sky, Water } from 'three/examples/jsm/Addons.js'

interface WaterOption {
    debug?: Boolean,
    scene: THREE.Scene,
    renderer: THREE.WebGLRenderer
}

export default function useWater(opt: WaterOption) {
    const { debug = true, scene, renderer } = opt || {}
    const gui = new dat.GUI()
    const WaterGroup = new THREE.Group();
    const waterGeometry = new THREE.PlaneGeometry(10000, 10000)

    const water = new Water(waterGeometry, {
        textureWidth: 512,
        textureHeight: 512,
        waterNormals: new THREE.TextureLoader().load('./source/textures/waternormals.jpg', function (texture) {
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping
        }),
        sunDirection: new THREE.Vector3(),
        sunColor: 0xffffff,
        waterColor: 0x001e0f,
        distortionScale: 3.7,
        fog: scene.fog !== undefined,
    })

    water.rotation.x = -Math.PI / 2

    gsap.timeline({
        repeat: -1,
        yoyo: true,
        onUpdate: () => {
            water.material.uniforms['time'].value += 1.0 / 60.0
        },
    })

    const sun = new THREE.Vector3()
    const sky = new Sky()
    sky.scale.setScalar(10000)

    const skyUniforms = sky.material.uniforms

    skyUniforms['turbidity'].value = 10
    skyUniforms['rayleigh'].value = 2
    skyUniforms['mieCoefficient'].value = 0.005
    skyUniforms['mieDirectionalG'].value = 0.8

    const parameters = {
        elevation: 2,
        azimuth: 180,
    }

    const pmremGenerator = new THREE.PMREMGenerator(renderer)
    let renderTarget: any

    function updateSun() {
        const phi = THREE.MathUtils.degToRad(90 - parameters.elevation)
        const theta = THREE.MathUtils.degToRad(parameters.azimuth)
        sun.setFromSphericalCoords(1, phi, theta)
        sky.material.uniforms['sunPosition'].value.copy(sun)
        water.material.uniforms['sunDirection'].value.copy(sun).normalize()
        if (renderTarget !== undefined) renderTarget.dispose()
        renderTarget = pmremGenerator.fromScene(scene)
        scene.environment = renderTarget.texture
    }
    updateSun()

    if (debug) {
        const folderWater = gui.addFolder('Water')
        folderWater.add(water.scale, 'x', 0.1, 3).name('X缩放').step(0.1)
        folderWater.add(water.scale, 'y', 0.1, 3).name('Y缩放').step(0.1)
        folderWater.open()

        const folderSky = gui.addFolder('Sky')
        folderSky.add(parameters, 'elevation', 0, 90, 0.1).onChange(updateSun)
        folderSky.add(parameters, 'azimuth', -180, 180, 0.1).onChange(updateSun)
        folderSky.open()
    }

    WaterGroup.add(water);
    WaterGroup.add(sky);

    return {
        water: WaterGroup,
    }
}